package com.example.common.util;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA 加密、解密、加签、验签 工具类
 *
 * @author zhoubin
 * @date 2019-05-25 20:43:03
 */
public class RSAUtil {

    public static final int KEY_SIZE = 1024;
    /**
     * 密钥算法
     */
    public static final String RSA_ALGORITHM = "RSA";
    /**
     * 加解密算法/工作模式/填充方式
     */
    public static final String RSA_ALGORITHM_STR = "RSA/ECB/PKCS1Padding";

    private static KeyPair keyPair;

    private static void init() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
            keyPairGenerator.initialize(KEY_SIZE);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取公钥
     *
     * @return
     */
    public static String getPubKey() {
        if (keyPair == null) {
            init();
        }
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        System.out.print("公钥:");
        String pubKey = new Base64().encodeToString(rsaPublicKey.getEncoded());
        System.out.println(pubKey);
        return pubKey;
    }

    /**
     * 获取私钥
     *
     * @return
     */
    public static String getPrvKey() {
        if (keyPair == null) {
            init();
        }
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        System.out.print("私钥:");
        // Base64.encodeBase64String() 和 new Base64().encodeToString() 方法加密结果一致
        String prvKey = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        System.out.println(prvKey);
        return prvKey;
    }

    /**
     * 私钥加密
     *
     * @param prvKey 私钥
     * @param param  要加密的字符串
     * @return
     */
    public static String encryptPrvKey(String prvKey, String param) {
        String encryptStr = null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            // 确定算法
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM_STR);
            // 格式化私钥
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(prvKey));
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            // 确定加密密钥
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            // 加密
            byte[] result = cipher.doFinal(param.getBytes());
            encryptStr = Base64.encodeBase64String(result);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return encryptStr;
    }

    /**
     * 私钥解密
     *
     * @param data
     * @param prvKey
     * @return
     */
    public static String decryptPrvKey( String data,String prvKey) {

        String encryptStr = null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            // 确定算法
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            // 格式化私钥
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(prvKey));
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            // 确定加密密钥
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            // 解密
            encryptStr = new String(cipher.doFinal(Base64.decodeBase64(data)));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return encryptStr;
    }

    /**
     * 公钥解密
     *
     * @param pubKey 公钥
     * @param param  私钥加密的字符串
     * @return
     */
    public static String decryptPubKey(String pubKey, String param) {
        String decryptStr = null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            // 确定算法
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM_STR);

            // 格式化公钥
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(pubKey));
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            // 确定公钥
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            // 解密
            decryptStr = new String(cipher.doFinal(Base64.decodeBase64(param)));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return decryptStr;
    }

    public static void main(String[] args) {

//        String prvKey = RSAUtil.getPrvKey();
//        String pubKey = RSAUtil.getPubKey();
//        String param = RSAUtil.encrypt(prvKey, "ss");

        String prvKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ7/QqVidBDsSWuNaMLsZuqx4sZYZamrP3sqkMxLOkcibepQAfQqZwm1z3A/aEfyTXrSs1RarKl1Vx5394ckLW5pVEgaDL98gPQ1UeSf+jD2Q9ssiQyUSM1mlplAn2kNzE0LnoV63AH11SMIeYJMNzyDbMNnVv7kTfX1Zw/iwULxAgMBAAECgYAXjMFnU6TTWNwrFP/eVzuLKZvoOvGb5uR5Lr3RtJbGMIBNQ1p2us0WMBqwioO8nFQDjC/Jn8CRPPMRbT15g89CnnPyEh9UYHIhnaCHvNaE6wgnCwVpyMG68rLcxJH3yd7Ny74hxEToGVIWfDfh09nBMNfhHSaee4+FLOsPipOtUQJBANW1L73+6Ludod3KgLozl6PVZx09e9+vl1b8fKUtDKGjeVRyDhA/fxaaqVkXEJq5BDLkVOwEuGr1BBPCJO1iSwUCQQC+dlXipl2TpTZXJ+KOV+tGHRCuyQ1CZBqzfLGgx+5Y1spP+qlNlWhBg75uQrduCurXlfY/aNwpLJ6INUUcKNP9AkB0Py+uGPf9/jvrSlkFcET/MHj7ldNJFNmszoD61Gt3jVXVUolF21RFNnIB7SLyFswq5rsu+05Zl9fU65lsqzgFAkAqJHrqdI8+DQ9SB5Q8lL2NPP8k/X1+lDHIRy3yemqFo7kOK1NsxENWQ7VOJlr58VZ3L0pWS3hzb9kAIHFTQsFtAkEAk0KVAap3Sc54Cgc1YYctEAYPE7PfqhJwTeM3pHysthPGdWWvipo3z3ieTxyTA9GfTc+Qk2sAcctTZj91Niqztw==";
        String pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCe/0KlYnQQ7ElrjWjC7GbqseLGWGWpqz97KpDMSzpHIm3qUAH0KmcJtc9wP2hH8k160rNUWqypdVced/eHJC1uaVRIGgy/fID0NVHkn/ow9kPbLIkMlEjNZpaZQJ9pDcxNC56FetwB9dUjCHmCTDc8g2zDZ1b+5E319WcP4sFC8QIDAQAB";
        String param = "miBLjCJbyyD3WSz8dmKpk6YJc3j+QsEhbXTV1SqkIqkqQfbl2719K2hdWliQr89RRoYRrzLpcei/0YiuczieLZLXMGxlGB6obG9vzt7l9Lkyy67vs910J4mFQEVi4mFRghy1M388hPIcsQ53hYcNPkCJrxihHEO9gfQUsHfEPnQ=";


        String result = RSAUtil.decryptPubKey(pubKey, param);

        System.out.println("加密结果:" + param);
        System.out.println("解密结果:" + result);

    }

}
